home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 October: Technology Seed / ADC Seed CD - October 1999.toast / FireWire / FireWire_2.0_SDK / Source / SBP2 / FWSBP2DiskDriver / FWSBP2DiskDriver.c next >
Encoding:
Text File  |  1999-04-12  |  63.4 KB  |  2,082 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        FWSBP2DiskDriver.c
  3.  
  4.     Contains:    Sample SBP-2 Hard Disk driver
  5.  
  6.     Version:    1.0
  7.  
  8.     Copyright:    © 1998-1999 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     File Ownership:
  11.  
  12.         DRI:                Clinton Bauder
  13.  
  14.         Other Contact:        Eric Anderson
  15.  
  16.         Technology:            FireWire
  17.  
  18.     Writers:
  19.  
  20.         (EA)    Eric Anderson (ewa)
  21.         (DCB)    Clinton Bauder
  22.  
  23.     Change History (most recent first):
  24.  
  25.       <FW32>     3/15/99    DCB        Mask the incoming buffer with 0x0000000F instead of 0x00000007
  26.                                     when deciding to double buffer as some devices have trouble with
  27.                                     the smaller alignment restriction.
  28.       <FW31>      3/8/99    DCB        Lengthen the timeout for TURs to 5 seconds. Some devices don't
  29.                                     like a LUNReset command while a TUR is still active.
  30.       <FW30>      3/8/99    DCB        Slight improvement in the way we handle ReadCapacity commands.
  31.                                     Some devices after a crash can get into a state where the return
  32.                                     good status for this command but don't actually send us any
  33.                                     data. Now if we don't get a valid capacity we return an error up
  34.                                     the chain and don't load the driver. I'm investigating ways to
  35.                                     reset the drive to fix the problem for real but this is better
  36.                                     than creating a bogus drive queue element and risking erasing
  37.                                     the volume.
  38.       <FW29>      3/8/99    DCB        And one more change. Changed the TheDFMDescriptor ranges for
  39.                                     VendorID and SoftwareRev to "don't care" from "match
  40.                                     everything". This makes it easier for "real" drivers with more
  41.                                     specific DFMDescriptors to override this driver.
  42.       <FW28>      3/8/99    DCB        Lots of cleanup and some real improvements too. Now if
  43.                                     needLUNReset is set true in the header file we use the
  44.                                     FWSBP2Manage function to reset the LUN before resetting the
  45.                                     fetch agent. Allows us to recover from bad packets on devices
  46.                                     that don't always respond to a fetch agent reset (you know who
  47.                                     you are...). Also cleaned up the state variables for keeping
  48.                                     track of logins. Now logout on eject control call to spin down
  49.                                     the disk. Also make sure we're done logging out before
  50.                                     de-allocating the login ORB if our initial login failed.
  51.       <FW27>      3/4/99    DCB        Two things: Fixed a performance issue with double buffering for
  52.                                     reads. We were blockmoving the size of the whole buffer for each
  53.                                     chunk, not the chunk size. Second add support for verifying
  54.                                     writes. Sorry about the clutter but it is pretty useful for
  55.                                     tracking down data corruption problems.
  56.       <FW26>      3/2/99    DCB        Add support for a bunch of DriverGestalt calls. Also now if we
  57.                                     get login failed notification we try to login again on the
  58.                                     assumption that we were unplugged or reset during a login.
  59.       <FW25>     2/15/99    DCB        Add better support for 2 macs-1 drive, that is do the right
  60.                                     thing if we fail a login.
  61.       <FW24>     2/15/99    DCB        Add support for Eric's notification changes. Basically now we
  62.                                     assume ORBs are canceled immediately following a reset. Also
  63.                                     don't bother paying attention to resets if we are waiting for a
  64.                                     re-plug. Let FSL do that for us.
  65.       <FW23>     2/12/99    EA        Changed max payload size to 256 for now.
  66.       <FW22>      2/8/99    DCB        Make the DFMDescriptor and DriverDescriptor more correct (and
  67.                                     specific).
  68.       <FW21>     1/25/99    DCB        Misc. Cleanup of the re-plug code. Handle loginFailed responses
  69.                                     better. Try to prevent re-entrant us of resources related to
  70.                                     logging in after the reconnect timeout fails.
  71.       <FW20>     1/21/99    DCB        Clear the gotEject flag on a login so we know the drive is
  72.                                     around and don't inadvertently return errors.
  73.       <FW19>     1/21/99    DCB        Cleaned up the hot-unplugging code to get rid of the unnecessary
  74.                                     DeviceNotify stuff and use instead the brand new
  75.                                     FWWaitForDeviceRePlug() API I just invented. Now we get a DSAT
  76.                                     warning if the drive goes away unexpectedly. If the user cancels
  77.                                     this with Command-. we start returning ioErr until the drive
  78.                                     returns.
  79.       <FW18>     1/19/99    EA        Fixed FlashSymbiosROM to set the generation value so that the
  80.                                     flag kFWAsynchFailOnBusReset will work as intended.
  81.       <FW17>     1/19/99    DCB        Clean up some comments and the Finalize routine (still never
  82.                                     called but it should at least show what should be done).
  83.       <FW16>     1/19/99    DCB        Did a couple of things. First we now nearly always recover from
  84.                                     a hot unplug followed by a re-plug. Occasionally we don't get
  85.                                     ORB notification for an outstanding ORB if the re-plug happens
  86.                                     before the reconnect fails. Unplugging and replugging again
  87.                                     fixes this. The bug appears to be in FSL. I also added a boolean
  88.                                     in the eject code which we use to keep track of whether the disk
  89.                                     has been unmounted. If so we post a diskEvt every time we login.
  90.                                     This way the drive re-appears when re-plugged after being
  91.                                     unmounted and unplugged. User dialogs asking for a disk to be
  92.                                     inserted when hot unplugged while a volume is mounted are not
  93.                                     implemented yet. Stay tuned.
  94.       <FW15>     1/15/99    EA        Changed to set the BUSY_TIMEOUT register in the drive so that it
  95.                                     will retry busy packets.  This works (helps?) on the LSI Native
  96.                                     Bridge.  Removed kFWCommandSyncFlag from asynch command flags
  97.                                     (it is a plain command flag, and those are different).  Gave
  98.                                     FlashSymbiosROM its own command object but did not test this as
  99.                                     I have no card to flash.
  100.       <FW14>     1/15/99    DCB        Don't return an error from eject. This allows us to unmount the
  101.                                     drive before unplugging it without getting an annoying error
  102.                                     from the finder.
  103.       <FW13>     1/15/99    DCB        Nearly almost have hot-unplugging and re-plugging working. See
  104.                                     my comment block in the device notification section for details
  105.                                     on why it doesn't _quite_ work yet.
  106.       <FW12>      1/3/99    EA        Changed to set kSBP2CommandNormalORB flag for normal ORBs.
  107.       <FW11>    12/31/98    EA        Changed to pre-allocate 12288 bytes of storage for each normal
  108.                                     command object, as per the latest SBP-2 API document.
  109.       <FW10>    12/29/98    DCB        Double buffer requests if the buffer passed in from the OS is
  110.                                     not aligned to a cache line. SBP is unclear on whether this is
  111.                                     required but some devices clearly need it.
  112.        <FW9>    12/23/98    DCB        Don't do ReqSense anymore as some drives don't like this. Back
  113.                                     to straight retries for error checking. Also fixed up the
  114.                                     Symbios ROM flash code.
  115.        <FW8>    12/19/98    DCB        Minor cleanup of the sample Symbios ROM and ATA mode code at the
  116.                                     end of this file.
  117.        <FW7>    12/18/98    DCB        Make sure we wait for login before trying to use the fetch
  118.                                     agent.
  119.        <FW6>    12/18/98    DCB        Fix some things up for native bridge support. Make request sense
  120.                                     calls now when fetch agent goes dead. Much better threading and
  121.                                     error recovery when we write to the fetch agent's reset
  122.                                     register.
  123.        <FW5>     12/7/98    EA        Removed brand name from comment.
  124.        <FW4>     12/1/98    EA        Changed to set maximum payload size to 512 in login command
  125.                                     object (default is 4, but it wasn't previously enforced).
  126.        <FW3>    11/20/98    DCB        Use Eric's new API to decide which ORB we just got notification
  127.                                     for. Also clean up some comments.
  128.        <FW2>    11/17/98    DCB        Misc Cleanup.
  129.        <FW1>    11/17/98    DCB        first checked in
  130.        <FW3>    10/28/98    DCB        Using new defs for matching SBP drivers. This allows us to be
  131.                                     much more specific in our decision as to which driver belongs to
  132.                                     which device.
  133.        <FW2>     9/20/98    EA        Filled in header comments.
  134.        <FW1>     9/20/98    EA        first checked in
  135. */
  136.  
  137.  
  138. #include <Types.h>
  139. #include <Files.h>
  140. #include <Errors.h>
  141. #include <Disks.h>
  142. #include <DriverGestalt.h>
  143. #include <OSUtils.h>
  144. #include <Devices.h>
  145. #include <DriverServices.h>
  146. #include <LowMem.h>
  147. #include <FireWire.h>
  148. #include <FireWireSBP2.h>
  149. #include <SampleSBP2.h>
  150. #include <FWSBP2DiskDriver.h>
  151. /*zzz*/
  152. #include <TextUtils.h>
  153. #include <stdio.h>
  154. char    debugStr[256];
  155. /*zzz*/
  156.  
  157.  
  158. ////////////////////////////////////////////////////////////////////////////////
  159. //
  160. // Notes and Caveats
  161. //
  162. // This is an example of how to use SPB rather than an example of a complete
  163. // hard disk driver. It is, in fact, a long way from being a shipping product
  164. // and should be viewed as such.
  165. //
  166. // This driver uses the whole hard disk and doesn't understand partitions.
  167. //
  168. // Support for immediate calls is suspect at best.
  169. //
  170. // Error handling consists entirely of retries no matter what went wrong.
  171. //
  172. // DriverGestalt call support is a bit minimal (but better than what it was).
  173. //
  174. // The DFMDescriptor in this file is quite imprecise and will install this driver
  175. // on a wide variety of devices. Some disk drives incorrectly report their 
  176. // device_type as 0x0e instead of 0x00. The example tries to run both on drives
  177. // with the correct value and those with the value of 0x0e. Real shipping drivers
  178. // will need to be more precise.
  179. //
  180. // This driver makes no attempt to manage or handle bus power. It should use
  181. // the power APIs in FireWire 2.0 to ask if there is enough power to spin up
  182. // the drive before logging in (assuming the drive is bus powered).
  183. //
  184. // No attempt is made to provide exclusive access to one client save the normal
  185. // SBP2 login. Which mac gets a drive after it shows up on a local FireWire net
  186. // is strictly first come first serve. This is true even after a re-plug when one
  187. // of the Macs might have a volume mounted. In this case if another Mac gets the
  188. // login bad things will happen.
  189.  
  190. ////////////////////////////////////////////////////////////////////////////////
  191. //
  192. // Internal procedure prototypes.
  193. //
  194.  
  195. static OSStatus    FWSBP2Initialize (
  196.     RegEntryIDPtr                pRegEntryID,
  197.     SInt16                        refNum);
  198.  
  199. static OSStatus    FWSBP2Terminate (void);
  200.  
  201. static OSStatus    SBP2Logout ( void );
  202.  
  203. static OSStatus SBP2DoReadWriteBlocks(
  204.     Boolean            isWrite,
  205.     UInt32             count,
  206.     UInt32             sector,
  207.     Ptr             buffer,
  208.     Boolean            sync ) ;
  209.  
  210. static OSStatus FWSBP2Prime(
  211.     AddressSpaceID                addressSpaceID,
  212.     IOCommandID                    ioCommandID,
  213.     IOCommandContents            ioCommandContents,
  214.     IOCommandKind                ioCommandKind,
  215.     Boolean                        isWrite);
  216.  
  217. static OSStatus SBP2Control (
  218.     AddressSpaceID                addressSpaceID,
  219.     IOCommandID                    ioCommandID,
  220.     IOCommandContents            ioCommandContents,
  221.     IOCommandKind                ioCommandKind);
  222.  
  223. static OSStatus SBP2Status (
  224.     AddressSpaceID                addressSpaceID,
  225.     IOCommandID                    ioCommandID,
  226.     IOCommandContents            ioCommandContents,
  227.     IOCommandKind                ioCommandKind);
  228.  
  229. static OSStatus SBPLoginNotify(
  230.     FWClientSBP2NotifyParamsPtr    pFWClientSBP2NotifyParams,
  231.     UInt32                        *pCommandAcceptance);
  232.  
  233. static OSStatus SBPStatusNotify(
  234.     FWClientSBP2NotifyParamsPtr    pFWClientSBP2NotifyParams,
  235.     UInt32                        *pCommandAcceptance);
  236.  
  237. static OSStatus SBPUnsolicitedStatusNotify(
  238.     FWClientSBP2NotifyParamsPtr    pFWClientSBP2NotifyParams,
  239.     UInt32                        *pCommandAcceptance);
  240.     
  241. static OSStatus SBP2CalculateMediaSize( void );
  242.  
  243. void ResetFACompletionProc(
  244.     FWCommandObjectID            fwCommandObjectID,
  245.     OSStatus                    commandStatus,
  246.     UInt32                        completionProcData);
  247.     
  248. void LoginCompletionProc(
  249.     FWCommandObjectID            fwCommandObjectID,
  250.     OSStatus                    commandStatus,
  251.     UInt32                        completionProcData);
  252.  
  253. void ManageCompletionProc(
  254.     FWCommandObjectID            fwCommandObjectID,
  255.     OSStatus                    commandStatus,
  256.     UInt32                        completionProcData);
  257.  
  258. void ReconnectReadCompletionProc(
  259.     FWCommandObjectID            fwCommandObjectID,
  260.     OSStatus                    commandStatus,
  261.     UInt32                        completionProcData);
  262.  
  263. void ReplugCompletionProc(
  264.     FWCommandObjectID            fwCommandObjectID,
  265.     OSStatus                    commandStatus,
  266.     UInt32                        completionProcData);
  267.  
  268. static OSStatus SBP2TUR( Boolean sync );
  269.  
  270. static OSStatus FlashSymbiosROM( void );
  271.  
  272. static OSStatus SetBUSY_TIMEOUT (void);
  273.  
  274. static OSStatus    FWSBPResetNotify (
  275.     FWClientInterfaceParamsPtr    pFWClientInterfaceParams,
  276.     UInt32                        *pCommandAcceptance);
  277.  
  278. static void FWSBPLookForDrive( void );
  279.  
  280. ////////////////////////////////////////////////////////////////////////////////
  281. //
  282. // The driver descriptor.
  283. //
  284.  
  285. DriverDescription             TheDriverDescription =
  286. {
  287.     kTheDescriptionSignature,
  288.     kInitialDriverDescriptor,
  289.     {
  290.         "\psbp609e,104d8",        // Official Mass Storage values
  291.         1, 0, finalStage, 1,
  292.     },
  293.     {
  294.         kDriverIsUnderExpertControl |
  295.         kDriverIsOpenedUponLoad,
  296.         "\p.FWSBP2DiskDriver",
  297.     },
  298.  
  299.     1,
  300.     kServiceCategoryNdrvDriver,
  301.     kNdrvTypeIsBlockStorage,
  302.     1,0,0,0
  303. };
  304.  
  305. // Should match above. Probably needs to come from the same constants...
  306. const NumVersion gFWDiskVersion = {1, 0, finalStage, 0};
  307.  
  308. ////////////////////////////////////////////////////////////////////////////////
  309. //
  310. // A quick note on how this works:
  311. //
  312. // The SBP2Expert creates sub-nodes for each LUN 
  313. // ...:firewire:fw609e,10483
  314. // ...:firewire:fw609e,10483:sbpXXXXXX,YYYYYY
  315. // ...:firewire:fw609e,10483:sbpPPPPPP,QQQQQQ
  316. //
  317. // XXXXXX is the command_set_spec_ID of lun 0.  YYYYYY is the command_set of lun 0.
  318. // PPPPPP is the command_set_spec_ID if lun 1.  QQQQQQ is the command_set of lun 1.  etc.
  319. //
  320. // The name of the driver then should match the sub-node created by the expert. To further
  321. // narrow down the match the SBP2Expert creates a table with the VendorID, SoftwareRev,
  322. // FirmwareRev, LUN and device_type values from the CSR ROM. This table is contained  in
  323. // a property called "TheDFMTable". The format for this table is in FireWireSBP2.h.
  324. // A similar table is exported by the driver and is called TheDFMDescriptor. It is exactly
  325. // twice the size of TheDFMTable as it contains a range for each value exported by the expert.
  326. // Drivers which match the greatest number of values in the table are selected to match the
  327. // device. Fields with a negative range are marked as "don't care". 
  328. //
  329. // Note that "don't care" is different from matching everything. Matching everything means
  330. // the score for the driver will be incremented for that field while don't care means that
  331. // it won't be. Thus a driver with 3 matches and 1 don't care scores lower than a driver
  332. // with 4 matches - even if the matches are the 0 through 0xFFFFFFFF type.
  333. //
  334. // Drivers with identical scores will be ranked by version as with other native drivers.
  335.  
  336.  
  337. // This particular DFMDescriptor isn't very specific. A real driver will need to better
  338. // identify the device it works with.
  339.  
  340. SBPMatchData                        TheDFMDescriptor = 
  341. {
  342.     0x00000000, 0xFFFFFFFF,            // VendorID, don't care
  343.     0x00000000, 0xFFFFFFFF,            // SoftwareRev, don't care
  344.     0x00000000, 0xFFFFFFFF,            // FirmwareRev, don't care 
  345.     0x00000000, 0x00000000,            // LUN, match 0x00000000 
  346.     0x00000000, 0x00000000            // device_type, match 0x00000000 
  347. };
  348.  
  349. ////////////////////////////////////////////////////////////////////////////////
  350. //
  351. // Our ICON.
  352. //
  353.  
  354. static UInt32 staticIconData[64] =
  355. {
  356.     0xFFFFFFFF, 0x80000001, 0x80000001, 0x80000001,
  357.     0x80000001, 0x80400201, 0x80A00501, 0x81400881,
  358.     0x82881041, 0x85142021, 0x82281041, 0x80500881,
  359.     0x80A3C501, 0x80442201, 0x80081001, 0x80081001,
  360.     0x80081001, 0x80081001, 0x80042001, 0x8003C001,
  361.     0x80000001, 0x8007E001, 0x80042001, 0x8007E001,
  362.     0x80000001, 0x8007E001, 0x80042001, 0x8007E001,
  363.     0x80000001, 0x80000001, 0x80000001, 0xFFFFFFFF,
  364.     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
  365.     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
  366.     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
  367.     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
  368.     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
  369.     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
  370.     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
  371.     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
  372. };
  373.  
  374.  
  375. ////////////////////////////////////////////////////////////////////////////////
  376. //
  377. // Global driver data.
  378. //
  379.  
  380. FWSBP2DriverDataPtr                gpFWSBP2DriverData = nil;
  381.  
  382.  
  383. ////////////////////////////////////////////////////////////////////////////////
  384. //
  385. // DoDriverIO
  386. //
  387. //   Main entry point.
  388. //
  389.  
  390. OSErr    DoDriverIO(
  391.     AddressSpaceID                addressSpaceID,
  392.     IOCommandID                    ioCommandID,
  393.     IOCommandContents            ioCommandContents,
  394.     IOCommandCode                ioCommandCode,
  395.     IOCommandKind                ioCommandKind)
  396. {
  397.     OSErr                        err = noErr;
  398.  
  399.     switch (ioCommandCode)
  400.     {
  401.         case kInitializeCommand :
  402.             err = FWSBP2Initialize (&ioCommandContents.initialInfo->deviceEntry, ioCommandContents.initialInfo->refNum);
  403.             break;
  404.  
  405.         case kFinalizeCommand :
  406.             err = FWSBP2Terminate ();
  407.  
  408.         case kOpenCommand :
  409.             break;
  410.  
  411.         case kReadCommand :
  412.             err = FWSBP2Prime (addressSpaceID,
  413.                         ioCommandID,
  414.                         ioCommandContents,
  415.                         ioCommandKind,
  416.                         false);
  417.             break;
  418.  
  419.         case kWriteCommand :
  420.             err = FWSBP2Prime (addressSpaceID,
  421.                         ioCommandID,
  422.                         ioCommandContents,
  423.                         ioCommandKind,
  424.                         true);
  425.             break;
  426.         case kCloseCommand :
  427.             err = SBP2Logout();
  428.             break;
  429.  
  430.         case kControlCommand :
  431.             err = SBP2Control(addressSpaceID,
  432.                         ioCommandID,
  433.                         ioCommandContents,
  434.                         ioCommandKind);
  435.             break;
  436.  
  437.         case kStatusCommand :
  438.             err = SBP2Status(addressSpaceID,
  439.                         ioCommandID,
  440.                         ioCommandContents,
  441.                         ioCommandKind);
  442.             err = statusErr;
  443.             break;
  444.  
  445.         default :
  446.             err = paramErr;
  447.     }
  448.  
  449.     return (err);
  450. }
  451.  
  452.  
  453. ////////////////////////////////////////////////////////////////////////////////
  454. //
  455. // FWSBP2Initialize
  456. //
  457. //   This routine initializes the FireWire SBP2 sample driver.  It
  458. // allocates a private data record and registers with the FireWire family.
  459. // It also prepares some command objects for use later on.
  460. //
  461.  
  462. static OSStatus SBPLoginNotify(
  463.     FWClientSBP2NotifyParamsPtr    pFWClientSBP2NotifyParams,
  464.     UInt32                        *pCommandAcceptance);
  465.  
  466. static OSStatus    FWSBP2Initialize(
  467.     RegEntryIDPtr                pRegEntryID,
  468.     SInt16                        refNum)
  469. {
  470.     FWSBP2DriverDataPtr            pFWSBP2DriverData = nil;
  471.     FWDriverID                    fwDriverID;
  472.     QHdrPtr                        pDrvQHdr;
  473.     DrvQElPtr                    pDrvQEl;
  474.     short                        driveNum;
  475.     UInt32                        orbNum;
  476.     UInt32                        keepTrying;
  477.     OSStatus                    status = noErr;
  478.  
  479.     // Allocate our driver data.
  480.     pFWSBP2DriverData =
  481.         (FWSBP2DriverDataPtr) PoolAllocateResident (sizeof (FWSBP2DriverData), true);
  482.     if (pFWSBP2DriverData == nil)
  483.     {
  484.         status = memFullErr;
  485.     }
  486.     else 
  487.         gpFWSBP2DriverData = pFWSBP2DriverData;
  488.  
  489.     // Register with the FireWire family.
  490.     if (status == noErr)
  491.     {
  492.         status = FWRegisterDriver (pRegEntryID,
  493.                                    &fwDriverID,
  494.                                    &(pFWSBP2DriverData->csrUnitID),
  495.                                    (UInt32) pFWSBP2DriverData);
  496.  
  497.         if (status == noErr)
  498.             pFWSBP2DriverData->fwDriverID = fwDriverID;
  499.             
  500.     }
  501.  
  502.     // Set the maximum packet payload size.
  503.     if (status == noErr)
  504.     {
  505.         status = FWSetMaxPayloadSize ((FWReferenceID) pFWSBP2DriverData->fwDriverID, kDiskDriverPayloadSize);
  506.     }
  507.  
  508.     // Allocate login command object.
  509.     if (status == noErr)
  510.     {
  511.         status = FWAllocateSBP2LoginCommandObject ((FWReferenceID) pFWSBP2DriverData->fwDriverID,
  512.                                                    &pFWSBP2DriverData->loginCommandID);
  513.     }
  514.     
  515.     if (status != noErr) pFWSBP2DriverData->loginCommandID = 0;
  516.  
  517.     // Prepare login command object.
  518.     if (status == noErr)
  519.     {
  520.         status = FWSetSBP2LoginCommandFlags (pFWSBP2DriverData->loginCommandID,
  521.                                              kSBP2NotifyOnLoginComplete |
  522.                                              kSBP2NotifyOnLoginFailed |
  523.                                              kSBP2NotifyOnReconnecting |
  524.                                              kSBP2NotifyOnReconnectComplete |
  525.                                              kSBP2NotifyOnReconnectFailed |
  526.                                              kSBP2ExclusiveLogin );
  527.     }
  528.     
  529.     if (status == noErr)
  530.     {
  531.         status = FWSetSBP2LoginCommandLoginNotifyProc (pFWSBP2DriverData->loginCommandID,
  532.                                                        SBPLoginNotify,
  533.                                                        (UInt32) pFWSBP2DriverData);
  534.     }
  535.  
  536.     if (status == noErr)
  537.     {
  538.         status = FWSetSBP2LoginCommandStatusNotifyProc (pFWSBP2DriverData->loginCommandID,
  539.                                                         SBPStatusNotify,
  540.                                                         (UInt32) pFWSBP2DriverData);
  541.     }
  542.  
  543.     if (status == noErr)
  544.     {
  545.         status = FWSetSBP2LoginCommandUnsolicitedStatusNotifyProc (pFWSBP2DriverData->loginCommandID,
  546.                                                         SBPUnsolicitedStatusNotify,
  547.                                                         (UInt32) pFWSBP2DriverData);
  548.     }
  549.  
  550.     if (status == noErr)
  551.     {
  552.         status = FWSetFWCommandCompletionProc (pFWSBP2DriverData->loginCommandID,
  553.                                                         LoginCompletionProc);
  554.     }
  555.  
  556.     if (status == noErr)
  557.     {
  558.         status = FWSetSBP2LoginCommandMaxPayloadSize (pFWSBP2DriverData->loginCommandID, kDiskDriverPayloadSize );
  559.     }
  560.     
  561.     if( status == noErr)
  562.     {
  563.         status = FWAllocateSBP2ManagementCommandObject((FWReferenceID) pFWSBP2DriverData->fwDriverID,
  564.                                                    &pFWSBP2DriverData->fwLUNReset_ID);
  565.     }
  566.     
  567.     if( status == noErr )
  568.     {
  569.         status = FWSetSBP2ManagementCommandFunction(pFWSBP2DriverData->fwLUNReset_ID, kSBP2LogicalUnitReset);
  570.     }
  571.     
  572.     if( status == noErr )
  573.     {
  574.         status = FWSetSBP2ManagementCommandCommandID( pFWSBP2DriverData->fwLUNReset_ID,
  575.                                                         pFWSBP2DriverData->loginCommandID);
  576.     }
  577.  
  578.     if (status == noErr)
  579.     {
  580.         status = FWSetFWCommandCompletionProc (pFWSBP2DriverData->fwLUNReset_ID,
  581.                                                         ManageCompletionProc);
  582.     }
  583.  
  584.     for( orbNum = 0; orbNum < kTotalORBs; orbNum++ ) {
  585.         // Allocate an ORB command object.
  586.         if (status == noErr)
  587.         {
  588.             status = FWAllocateSBP2NormalCommandObject (pFWSBP2DriverData->loginCommandID,
  589.                                                         &pFWSBP2DriverData->orbID[orbNum]);
  590.             
  591.             // Memory is not automatically set aside for ORBs.  If we ever want to set up an
  592.             // ORB at non-task level, we will need to have memory allocated in advance.
  593.             
  594.             if (status == noErr)
  595.                 status = FWAllocateFWCommandObjectMemory (pFWSBP2DriverData->orbID[orbNum], 12288);
  596.         }
  597.         
  598.         if (status != noErr) {
  599.             pFWSBP2DriverData->orbID[orbNum] = 0;
  600.             break;
  601.         }
  602.         
  603.     }
  604.  
  605.     pFWSBP2DriverData->currentORB = kAsyncORB;    // Switch between kAsyncORB and kAsyncORB + 1
  606.                                                 // Makes debugging easier since we can see
  607.                                                 // each new request go by in FireBug and also
  608.                                                 // in the receive buffer of the FWIM
  609.                                                 // Not really needed though.
  610.         
  611.     // Allocate an async command object for writing to the AGENT_RESET register.
  612.     // Need this in case the drive goes out to lunch. Writing this register doesn't always
  613.     // work, sometimes a bus reset or even power cycle is required. I don't know why yet
  614.     if (status == noErr)
  615.     {
  616.         status = FWAllocateAsynchCommandObject (&pFWSBP2DriverData->fwAGENT_RESET_ID);
  617.     }
  618.     
  619.     if (status == noErr)
  620.     {
  621.         status = FWSetFWCommandParams (pFWSBP2DriverData->fwAGENT_RESET_ID,
  622.                                        pFWSBP2DriverData->fwDriverID,
  623.                                        0,
  624.                                        ResetFACompletionProc,
  625.                                        0);
  626.     }
  627.  
  628.     // Allocate an async command object for reading from the drive after it has gone
  629.     // away long enough for a reconnect to fail. We issue this read after any bus reset
  630.     // following a reconnect failed to see if our device came back.
  631.     if (status == noErr)
  632.     {
  633.         status = FWAllocateAsynchCommandObject (&pFWSBP2DriverData->fwReconnectID);
  634.     }
  635.     
  636.     if (status == noErr)
  637.     {
  638.         status = FWSetFWCommandParams (pFWSBP2DriverData->fwReconnectID,
  639.                                        pFWSBP2DriverData->fwDriverID,
  640.                                        0,
  641.                                        ReconnectReadCompletionProc,
  642.                                        0);
  643.     }
  644.  
  645.     // Allocate an async command object for requesting a replug if the drive
  646.     // went away on us while we have volumes mounted.
  647.     
  648.     if (status == noErr)
  649.     {
  650.         status = FWAllocateFWCommandObject (&pFWSBP2DriverData->fwReplugID);
  651.     }
  652.     
  653.     if (status == noErr)
  654.     {
  655.         status = FWSetFWCommandParams (pFWSBP2DriverData->fwReplugID,
  656.                                        pFWSBP2DriverData->fwDriverID,
  657.                                        0,
  658.                                        ReplugCompletionProc,
  659.                                        0);
  660.     }
  661.  
  662.     // Save our driver data or clean up on error.
  663.     if (status == noErr)
  664.     {
  665.         
  666.         gpFWSBP2DriverData->drvrRefNum = refNum;
  667.         // And go ahead and login to the drive.
  668.         // !!!zzz realistically we need to make sure this drive
  669.         // belongs to us but for now we'll assume it does    
  670.         gpFWSBP2DriverData->pRegEntryID = *pRegEntryID;
  671.     
  672.         // BusManagementNotify didn't work...
  673.         FWSetFWClientResetNotifyProc(gpFWSBP2DriverData->fwDriverID, FWSBPResetNotify );
  674.         
  675.         pFWSBP2DriverData->loggedIn = false;
  676.         pFWSBP2DriverData->loginObjBusy = true;
  677.  
  678.         status = FWSBP2Login (gpFWSBP2DriverData->loginCommandID);
  679.             
  680.         while( gpFWSBP2DriverData->loginObjBusy )
  681.             ;
  682.     
  683.         if( !pFWSBP2DriverData->loggedIn ) {
  684.             return( openErr );
  685.         }
  686.     }
  687.     else
  688.     {//zzz should use terminate
  689.         if (pFWSBP2DriverData != nil)
  690.             PoolDeallocate ((Ptr) pFWSBP2DriverData);
  691.     }
  692.     
  693.     // If we got logged in, set the BUSY_TIMEOUT register so that the drive
  694.     // will retry if we busy a packet it sends us.
  695.     if (status == noErr)
  696.         status = SetBUSY_TIMEOUT ();
  697.     
  698.     // ••••••••••••
  699.     // Uncomment the following line if you want to flash a Symbios ROM for ATA rather than ATAPI.
  700.     // Only run it once and reset the bus afterwards.
  701.     // Unplug the 1394 cable and restart the Mac afterwards and replace the driver
  702.     // with one that doesn't do this after you have the ROM flashed.
  703.     //DebugStr("\pFlashSymbiosROM");
  704.     //FlashSymbiosROM();
  705.     
  706.     // Try a few of these - helps you wake up in the morning.
  707.     
  708.     keepTrying = 25;
  709.     while( keepTrying-- && SBP2TUR(true) ) 
  710.         ;
  711.     
  712.     if( status == noErr )
  713.         status = SBP2CalculateMediaSize();
  714.  
  715.     HLock((Handle)GetDCtlEntry (refNum));
  716.     gpFWSBP2DriverData->dce = *(GetDCtlEntry (refNum));
  717.     
  718.     // Set up stuff before drive queue element.
  719.     if (status == noErr)
  720.     {
  721.         gpFWSBP2DriverData->driveStatus.diskInPlace = 1;
  722.         gpFWSBP2DriverData->driveStatus.installed = 1;
  723.         gpFWSBP2DriverData->driveStatus.qType = 1;
  724.     }
  725.  
  726.     // Compute drive size.
  727.     if (status == noErr)
  728.     {
  729.         gpFWSBP2DriverData->driveStatus.driveSize = gpFWSBP2DriverData->totalBlocks & 0xFFFF;
  730.         gpFWSBP2DriverData->driveStatus.driveS1 = (short)(gpFWSBP2DriverData->totalBlocks >> 16);
  731.     }
  732.  
  733.     // Find a drive number to use, starting with number 8.
  734.     if (status == noErr)
  735.     {
  736.         driveNum = 8;
  737.         pDrvQHdr = GetDrvQHdr ();
  738.         pDrvQEl = (DrvQElPtr) (pDrvQHdr->qHead);
  739.         while (pDrvQEl)
  740.         {
  741.             if ((pDrvQEl->dQDrive == driveNum) ||
  742.                 ((pDrvQEl->dQDrive + 1) == driveNum))//zzz hack to work around AddDrive bug.
  743.             {
  744.                 driveNum++;
  745.                 pDrvQEl = (DrvQElPtr) (pDrvQHdr->qHead);
  746.             }
  747.             else
  748.             {
  749.                 pDrvQEl = (DrvQElPtr) pDrvQEl->qLink;
  750.             }
  751.         }
  752.  
  753.         gpFWSBP2DriverData->driveStatus.dQDrive = driveNum;
  754.     }
  755.  
  756.     // Add the drive to the drive queue.
  757.     if (status == noErr)
  758.     {
  759.         gpFWSBP2DriverData->queuedDQEl = true;
  760.         AddDrive (refNum,
  761.                   gpFWSBP2DriverData->driveStatus.dQDrive,
  762.                   (DrvQEl *) &(gpFWSBP2DriverData->driveStatus.qLink));
  763.     }
  764.  
  765.     // Notify interested parties that a new drive has been added.
  766.     //zzz should we check error?
  767.     if (status == noErr)
  768.     {
  769.         PostEvent (diskEvt, (UInt32) gpFWSBP2DriverData->driveStatus.dQDrive);
  770.     }
  771.     return status;
  772. }
  773.  
  774.  
  775. ////////////////////////////////////////////////////////////////////////////////
  776. //
  777. // FWSBP2Terminate
  778. //
  779. //   This routine terminates the FireWire SBP2 sample driver.  It
  780. // deallocates a private data record and unregisters with the FireWire family.
  781. //
  782. // Note, currently thi routine is never called.
  783. // Even if you unplug the device, nobody terminates the driver.
  784. //
  785.  
  786. static OSStatus    FWSBP2Terminate(void)
  787. {
  788.     OSStatus                    status = noErr;
  789.     UInt32                        orbNum;
  790.  
  791.     if (gpFWSBP2DriverData != nil)
  792.     {
  793.  
  794.         if (gpFWSBP2DriverData->loginCommandID)
  795.             FWDeallocateFWCommandObject (gpFWSBP2DriverData->fwAGENT_RESET_ID);
  796.  
  797.         if (gpFWSBP2DriverData->loginCommandID)
  798.             FWDeallocateFWCommandObject (gpFWSBP2DriverData->fwReconnectID);
  799.  
  800.         if( gpFWSBP2DriverData->queuedDQEl )
  801.             Dequeue( (QElemPtr)&gpFWSBP2DriverData->driveStatus.qLink, LMGetDrvQHdr() );
  802.  
  803.         //zzz We should check that ORB is not active before we deallocate it.
  804.         // We could issue a target reset to guarantee this.
  805.         
  806.         for( orbNum = 0; orbNum < kTotalORBs; orbNum++ ) {
  807.             if (gpFWSBP2DriverData->orbID[orbNum])
  808.                 FWDeallocateFWCommandObject (gpFWSBP2DriverData->orbID[orbNum]);
  809.         }
  810.  
  811.         if( gpFWSBP2DriverData->loggedIn )
  812.             SBP2Logout();
  813.         
  814.         if (gpFWSBP2DriverData->loginCommandID)
  815.             FWDeallocateFWCommandObject (gpFWSBP2DriverData->loginCommandID);
  816.  
  817.         // Unregister with FireWire family.
  818.         if (gpFWSBP2DriverData->fwDriverID != kInvalidFWDriverID)
  819.             FWUnregisterDriver (gpFWSBP2DriverData->fwDriverID);
  820.  
  821.         // Deallocate our driver data.
  822.         PoolDeallocate ((Ptr) gpFWSBP2DriverData);
  823.         gpFWSBP2DriverData = nil;
  824.     }
  825.  
  826.     return status;
  827. }
  828.  
  829.  
  830.  
  831. ////////////////////////////////////////////////////////////////////////////////
  832. //
  833. // SBP2Logout
  834. //
  835. //   This routine performs a logout.
  836. //
  837.  
  838. static OSStatus    SBP2Logout( void )
  839. {
  840.     OSStatus                    status = noErr;
  841.  
  842.     gpFWSBP2DriverData->loginObjBusy = true;
  843.  
  844.     status = FWSBP2Logout (gpFWSBP2DriverData->loginCommandID);
  845.     
  846.     while( gpFWSBP2DriverData->loginObjBusy )
  847.         ;
  848.     
  849.     if (status == noErr)
  850.         gpFWSBP2DriverData->loggedIn = false;
  851.     return noErr;
  852. }
  853.  
  854.  
  855. static OSStatus FWSBP2Prime(
  856.     AddressSpaceID                addressSpaceID,
  857.     IOCommandID                    ioCommandID,
  858.     IOCommandContents            ioCommandContents,
  859.     IOCommandKind                ioCommandKind,
  860.     Boolean                        isWrite)
  861. {
  862.     OSStatus                    status;
  863.     UInt32                        startblk; 
  864.     UInt32                        numblks;
  865.     IOParamPtr                    ioPB;
  866.     
  867.     // save away some info about the current command (assume single threaded for now).
  868.     gpFWSBP2DriverData->ioPB = ioPB = (IOParamPtr) ioCommandContents.pb;
  869.     gpFWSBP2DriverData->ioCommandID = ioCommandID;
  870.     gpFWSBP2DriverData->isWrite = isWrite;
  871.  
  872.     // calculate the starting block and block count (divide by 512) 
  873.     
  874.     if( ioPB->ioPosMode & 0x0100) {    // large volume format (>=4GB)
  875.         startblk =    ( *(UInt32 *)((char*)&(ioPB->ioPosOffset)+2) << (16-9) ) +
  876.                     ( *(UInt16 *)((char*)&(ioPB->ioPosOffset)+6) >> 9 );
  877.     }
  878.     else                                                // regular volume format (<4GB)
  879.         startblk = (UInt32)(ioPB->ioPosOffset) >> 9;
  880.  
  881.     numblks = (UInt32)(ioPB->ioReqCount) >> 9;
  882.  
  883.     // Is count an integer number of blocks or block out of range of partition ? 
  884.     if( ((ioPB->ioReqCount & (kBlockSize-1)) != 0)  ||
  885.                (startblk+numblks > gpFWSBP2DriverData->totalBlocks))  
  886.     {
  887.         status = paramErr;
  888.     } 
  889.     else 
  890.     {
  891.         gpFWSBP2DriverData->retriesLeft = 30; // Totally arbitrary, probably overkill
  892.         
  893.         gpFWSBP2DriverData->ioPending = true;
  894.         
  895.         // Can't hardly do nuthin if we aint logged in
  896.         if( !gpFWSBP2DriverData->loggedIn ) {
  897.         
  898.             // For immediate command just bail with IOErr
  899.             if( ioCommandKind == kImmediateIOCommandKind ) {
  900.                 return( ioErr );
  901.             }
  902.             else if( gpFWSBP2DriverData->returnDiskErr ) {
  903.                 // If user canceled our DSAT dialog return disk error to get clear any sync-wait
  904.                 // loops and allow the machine to keep operating. For all we know the reason the
  905.                 // drive went away was because the user spilled coffee on it and now they want
  906.                 // to save their open files somewhere else.
  907.                 IOCommandIsComplete (gpFWSBP2DriverData->ioCommandID, ioErr);
  908.                 return( ioErr );
  909.             }
  910.             else {
  911.                 // DSAT should still be on the screen, go away and wait for notification
  912.                 // and retry the command then.
  913.                 gpFWSBP2DriverData->count = numblks;
  914.                 gpFWSBP2DriverData->sector = startblk;
  915.                 gpFWSBP2DriverData->buffer = ioPB->ioBuffer;
  916.                 return( ioInProgress );
  917.             }
  918.         }
  919.  
  920.         // Make call synchronously if we are an immediate call, else normal
  921.         status = SBP2DoReadWriteBlocks( isWrite, numblks, startblk, ioPB->ioBuffer, ioCommandKind == kImmediateIOCommandKind );
  922.         
  923.         if( status == noErr ) 
  924.             gpFWSBP2DriverData->dce->dCtlPosition += (ioPB->ioActCount = ioPB->ioReqCount);
  925.         else if( status != ioInProgress ) {
  926.             status = ioErr;
  927.             ioPB->ioActCount = 0;            /* report all or none */
  928.         }
  929.     }
  930.     return(status);
  931. }
  932.  
  933.  
  934. ////////////////////////////////////////////////////////////////////////////////
  935. //
  936. // SBP2DoReadWriteBlocks
  937. //
  938. //   This routine reads block zero, assuming the target is a simple hard drive.
  939. // 
  940. //   The sync flag implies immediate. Don't ever call it with this flag true at
  941. //   interrupt time. This will be used for device manager immediate calls and
  942. //   probably partition map scanning code. Everything else should be asynchronous.
  943. //
  944.  
  945. static OSStatus SBP2DoReadWriteBlocks(
  946.     Boolean            isWrite,
  947.     UInt32             count,
  948.     UInt32             sector,
  949.     Ptr             buffer,
  950.     Boolean            sync ) 
  951. {
  952.     FWCommandObjectID            orbID;
  953.     OSStatus                    status;
  954. #if VerifyWrites
  955.     Boolean                        wasVerify;
  956. #endif
  957.     UInt8                        *command;
  958.  
  959.     // Remember some stuff for retries
  960.     gpFWSBP2DriverData->count = count;
  961.     gpFWSBP2DriverData->sector = sector;
  962.     gpFWSBP2DriverData->buffer = buffer;
  963.  
  964.     // Double buffer if not aligned to drive's liking
  965.     if( (long)buffer & 0x0000000F ) 
  966.         gpFWSBP2DriverData->doubleBuffer = true;
  967.     else
  968.         gpFWSBP2DriverData->doubleBuffer = false;
  969.     
  970. #if VerifyWrites
  971.     wasVerify = gpFWSBP2DriverData->needsVerify;
  972.     if( isWrite ) 
  973.         gpFWSBP2DriverData->needsVerify = true;
  974. #endif
  975.  
  976.     gpFWSBP2DriverData->xferLeft = 0;            // assume no extra transfer
  977.  
  978.  
  979.     if( count > kMaxTransfer ) {                // Transfer too big to do all at once?
  980.         gpFWSBP2DriverData->xferLeft = count-kMaxTransfer;
  981.         count = kMaxTransfer;
  982.         gpFWSBP2DriverData->next_block = sector + count;    
  983.  
  984. #if VerifyWrites
  985.         if( !wasVerify ) {
  986. #endif
  987.             gpFWSBP2DriverData->next_buffer = buffer + (count << 9);
  988. #if VerifyWrites
  989.         }
  990. #endif
  991.     } 
  992.  
  993.     if( isWrite && gpFWSBP2DriverData->doubleBuffer ) {
  994.         BlockMoveData(buffer, gpFWSBP2DriverData->dataBuffer, count << 9);
  995.     }
  996.     
  997.     if( sync )
  998.         orbID = gpFWSBP2DriverData->orbID[kImmedORB];
  999.     else {
  1000.         orbID = gpFWSBP2DriverData->orbID[gpFWSBP2DriverData->currentORB];
  1001.         
  1002.         // Switch to the other ORB for next transaction
  1003.         gpFWSBP2DriverData->currentORB = ( gpFWSBP2DriverData->currentORB ? 0 : 1);
  1004.     }
  1005.     
  1006.     // Prepare the ORB.
  1007.     // Page table total length must agree with ATAPI request length, or drive
  1008.     // will get confused.
  1009.     
  1010.     gpFWSBP2DriverData->buffers[0].addressHi = 0;
  1011.     
  1012.     if( gpFWSBP2DriverData->doubleBuffer )
  1013.         gpFWSBP2DriverData->buffers[0].addressLo = (UInt32) gpFWSBP2DriverData->dataBuffer;
  1014.     else
  1015.         gpFWSBP2DriverData->buffers[0].addressLo = (UInt32) buffer;
  1016.  
  1017.     gpFWSBP2DriverData->lengths[0] = (count << 9);
  1018.     status = FWSetSBP2NormalCommandBuffers (orbID, 1, gpFWSBP2DriverData->buffers, gpFWSBP2DriverData->lengths);
  1019.  
  1020.     // Form ATAPI command (SCSI-3, cribbed from MMC-2 spec)
  1021.     command = &gpFWSBP2DriverData->command[0];
  1022.  
  1023.     command[0] = (isWrite ? 0x2A : 0x28);            // Write or Read
  1024.     command[1] = 0;                                    // Mostly reserved
  1025.     command[2] = (sector >> 24) & 0xff;                // MSB of LBA
  1026.     command[3] = (sector >> 16) & 0xff;
  1027.     command[4] = (sector >> 8) & 0xff;
  1028.     command[5] = sector & 0xff;                        // LSB of LBA
  1029.     command[6] = 0;                                    // Reserved
  1030.     command[7] = (count >> 8) & 0xff;                // MSB of block count
  1031.     command[8] = count & 0xff;                        // LSB of block count
  1032.     command[9] = 0;                                    // Control (reserved)
  1033.     command[10] = 0;
  1034.     command[11] = 0x02;                                // Used DMA
  1035.  
  1036.     if (status == noErr)
  1037.         status = FWSetSBP2NormalCommandCommand (orbID, (Ptr) command, 12);
  1038.  
  1039.     if (status == noErr)
  1040.         status = FWSetSBP2NormalCommandTimeout (orbID, durationMillisecond * 1000);
  1041.     
  1042.     if (status == noErr)
  1043.         status = FWSetSBP2NormalCommandFlags (orbID,
  1044.                                               (isWrite ? 0 : kSBP2CommandTransferDataFromTarget) |
  1045.                                               kSBP2CommandCompleteNotify |
  1046.                                               kSBP2CommandImmediate |
  1047.                                               kSBP2CommandNormalORB);
  1048.  
  1049.     if( sync ) {
  1050.         if (status == noErr)
  1051.             status = FWSetFWCommandFlags (orbID, kFWCommandSyncFlag);
  1052.     }
  1053.     else {
  1054.         if (status == noErr)
  1055.             status = FWSetFWCommandFlags (orbID, 0);
  1056.     }
  1057.     
  1058.     
  1059.     if (status == noErr)
  1060.         status = FWAppendSBP2Command (orbID);
  1061.     
  1062.     if( (status == noErr) && sync )
  1063.     {
  1064.         // Wait for completion
  1065.         // Remember kiddies - don't do this at interrupt time!
  1066.         while( gpFWSBP2DriverData->immedStatus == ioInProgress )
  1067.             ;
  1068.         status = gpFWSBP2DriverData->immedStatus;
  1069.         if( !isWrite && gpFWSBP2DriverData->doubleBuffer ) {
  1070.             BlockMoveData( gpFWSBP2DriverData->dataBuffer, buffer, count << 9);
  1071.         }
  1072.     }
  1073.     
  1074.     if( (status == noErr) && !sync ) {
  1075.         return( ioInProgress );
  1076.     }
  1077.     return status;
  1078. }
  1079.  
  1080.  
  1081. ////////////////////////////////////////////////////////////////////////////////
  1082. //
  1083. // SBPLoginNotify
  1084. //
  1085. //   This routine is called when a login command completes.
  1086. //
  1087.  
  1088. static OSStatus SBPLoginNotify(
  1089.     FWClientSBP2NotifyParamsPtr    pFWClientSBP2NotifyParams,
  1090.     UInt32                        *pCommandAcceptance)
  1091. {
  1092.     
  1093.     gpFWSBP2DriverData->lookForDriveReqs = 0;    // Allow future login requests
  1094.  
  1095.     if (pFWClientSBP2NotifyParams->notificationEvent == kSBP2LoginComplete)
  1096.     {
  1097.         gpFWSBP2DriverData->loggedIn = true;
  1098.         gpFWSBP2DriverData->returnDiskErr = false;
  1099.         
  1100.         // If the user ejected the disk and then put it back we need to post a diskEvent to tell the File System
  1101.         if( gpFWSBP2DriverData->gotEject )
  1102.             PostEvent (diskEvt, (UInt32) gpFWSBP2DriverData->driveStatus.dQDrive);
  1103.  
  1104.         // Async login for reconnect? 
  1105.         if( gpFWSBP2DriverData->wasLoggedIn ) {
  1106.             
  1107.             if( gpFWSBP2DriverData->ioPending && gpFWSBP2DriverData->retriesLeft-- ) {
  1108.                 SBP2DoReadWriteBlocks( gpFWSBP2DriverData->isWrite, gpFWSBP2DriverData->count, gpFWSBP2DriverData->sector, gpFWSBP2DriverData->buffer, false);
  1109.             }
  1110.         }
  1111.         
  1112.         gpFWSBP2DriverData->wasLoggedIn = true;
  1113.         gpFWSBP2DriverData->gotEject = false; // volumes should be back.
  1114.         
  1115.         gpFWSBP2DriverData->fetchAgent.addressHi =
  1116.             *(((UInt32 *) (pFWClientSBP2NotifyParams->loginResponse)) + 1);
  1117.         gpFWSBP2DriverData->fetchAgent.addressLo =
  1118.             *(((UInt32 *) (pFWClientSBP2NotifyParams->loginResponse)) + 2);
  1119.         
  1120.     }
  1121.     
  1122.      if (pFWClientSBP2NotifyParams->notificationEvent == kSBP2Reconnecting)
  1123.      {
  1124.         // Sit on any incoming requests until we are reconnected. They'll fail anyway.
  1125.         gpFWSBP2DriverData->loggedIn = false;
  1126.  
  1127.      }
  1128.     
  1129.     if (pFWClientSBP2NotifyParams->notificationEvent == kSBP2ReconnectComplete)
  1130.      {
  1131.         gpFWSBP2DriverData->loggedIn = true;
  1132.         
  1133.         // Restart pending IO if it exists.
  1134.         if( gpFWSBP2DriverData->ioPending ) {
  1135.             if( gpFWSBP2DriverData->retriesLeft-- ) {
  1136.                 SBP2DoReadWriteBlocks( gpFWSBP2DriverData->isWrite, gpFWSBP2DriverData->count, gpFWSBP2DriverData->sector, gpFWSBP2DriverData->buffer, false);
  1137.             }
  1138.             else {
  1139.                 gpFWSBP2DriverData->ioPending = false;
  1140.                 IOCommandIsComplete (gpFWSBP2DriverData->ioCommandID, ioErr);
  1141.             }
  1142.         }
  1143.     }
  1144.      
  1145.      if (pFWClientSBP2NotifyParams->notificationEvent == kSBP2LoginFailed) {
  1146.         
  1147.         // is this is the first login?
  1148.         if( gpFWSBP2DriverData->wasLoggedIn ) {
  1149.             // Hmmm. Did somebody else log into our drive while it was off the bus
  1150.             // or did we get a reset or unplug while trying to login?
  1151.             // The latter seems more likely.
  1152.             //         Should look at status and/or use query logins to find out.
  1153.             // For now I'll assume we got unplugged or reset and try again. This is more 
  1154.             // useful for single initiator enviroments.
  1155.         
  1156.             gpFWSBP2DriverData->loggedIn = false;
  1157.             gpFWSBP2DriverData->wait4Replug = true;
  1158.             FWWaitForDeviceRePlug( gpFWSBP2DriverData->fwReplugID );
  1159.         }
  1160.         else
  1161.             gpFWSBP2DriverData->loggedIn = false;
  1162.     }
  1163.     
  1164.      if (pFWClientSBP2NotifyParams->notificationEvent == kSBP2ReconnectFailed) {
  1165.         
  1166.         // if we didn't expect the drive to go away demand that the user put it back
  1167.         // Important - this function is always asynchronous to allow FSL to make forward
  1168.         // progress. We'll find out what happend (came back or user cancelled with Command-.)
  1169.         // in the completion routine.
  1170.         
  1171.         gpFWSBP2DriverData->loggedIn = false;
  1172.         
  1173.         if( !gpFWSBP2DriverData->gotEject ) {
  1174.             gpFWSBP2DriverData->wait4Replug = true;
  1175.             FWWaitForDeviceRePlug( gpFWSBP2DriverData->fwReplugID );
  1176.         }
  1177.     
  1178.     }
  1179.     
  1180.     *pCommandAcceptance = kFWClientCommandAcceptNoMore;
  1181.     return FWClientCommandIsComplete (pFWClientSBP2NotifyParams->fwClientInterfaceParams.fwClientCommandID, 0);
  1182. }
  1183.  
  1184.  
  1185. ////////////////////////////////////////////////////////////////////////////////
  1186. //
  1187. // SBPStatusNotify
  1188. //
  1189. //   This routine is called when an ORB generates status.
  1190. //   This routine is a complete mess. I hate SBP2 error reporting. How may ways are
  1191. //   there to tell you something went wrong?
  1192. //
  1193.  
  1194. static OSStatus SBPStatusNotify(
  1195.     FWClientSBP2NotifyParamsPtr    pFWClientSBP2NotifyParams,
  1196.     UInt32                        *pCommandAcceptance)
  1197. {
  1198.     OSStatus                    compStatus;
  1199.     OSStatus                    status;
  1200.     OSStatus                    cmdStatus = ioErr;
  1201.     sbpStatusBlockPtr            sbpStatus;
  1202.     FWCommandObjectID            completedOrb;    // Which guy just finished
  1203.     Boolean                        statusValid = false;
  1204.     UInt32                        bufferLength;
  1205. #if VerifyWrites
  1206.     UInt32                        x;
  1207.     char                        debugStr[256];
  1208. #endif
  1209.     Boolean                        commandSuccessful = false;
  1210.  
  1211.     *pCommandAcceptance = kFWClientCommandAcceptNoMore;
  1212.     compStatus = FWClientCommandIsComplete (pFWClientSBP2NotifyParams->fwClientInterfaceParams.fwClientCommandID, 0);
  1213.  
  1214.     if( !gpFWSBP2DriverData->loggedIn && gpFWSBP2DriverData->ioPending ) {
  1215.         // Look for drive, try to login and restart whatever we were working on
  1216.         FWSBPLookForDrive();
  1217.         return( noErr );
  1218.     }    
  1219.     
  1220.     switch (pFWClientSBP2NotifyParams->notificationEvent)
  1221.     {
  1222.     
  1223.     case kSBP2NormalCommandStatus:
  1224.         if ((pFWClientSBP2NotifyParams->message) && (pFWClientSBP2NotifyParams->length)) {
  1225.             statusValid = true;
  1226.             sbpStatus = (sbpStatusBlockPtr)pFWClientSBP2NotifyParams->message;
  1227.             
  1228.             if( (sbpStatus->stSrcRespLen & 0x30) == 0 && sbpStatus->stSBPStatus == 0 ) {
  1229.             
  1230.                 if( (sbpStatus->stSrcRespLen & 0x07) == 1 ) {
  1231.                     
  1232.                     cmdStatus = noErr;
  1233.                 }
  1234.             }
  1235.             else if (sbpStatus->stSrcRespLen & 0x08) {
  1236.     
  1237.                 status = FWSetAsynchCommandParams
  1238.                     (gpFWSBP2DriverData->fwAGENT_RESET_ID,
  1239.                      0,                                                    // generation - ignored
  1240.                      gpFWSBP2DriverData->fetchAgent.addressHi,            // addr from login response
  1241.                      gpFWSBP2DriverData->fetchAgent.addressLo + 4,        // + 4 to get AGENT_RESET
  1242.                      (Ptr) gpFWSBP2DriverData,                            // any valid pointer will do
  1243.                      4,                                                    // quadlet write
  1244.                      0,                                                    // max payload - ignored
  1245.                      8,                                                    // max retries
  1246.                      0);                                                // no flags
  1247.                 
  1248.                 // Reset agent
  1249.                 if (status == noErr)
  1250.                 {
  1251.                     FWWrite (gpFWSBP2DriverData->fwAGENT_RESET_ID);
  1252.                     return( noErr );    // Pick up thread from completionProc and retry command
  1253.                 }
  1254.             }
  1255.         }
  1256.  
  1257.         // If no IO is in progress this was the Request Sense we did during initialization 
  1258.         // or some other IO not connected with an IO. Don't start retry state machine.
  1259.         if( !gpFWSBP2DriverData->ioPending )
  1260.             break;
  1261.             
  1262.         // If this was a prime command then either call ioDone or start
  1263.         // the next chunk of the transfer
  1264.         if( statusValid && (gpFWSBP2DriverData->command[0] == 0x2a || gpFWSBP2DriverData->command[0] == 0x28)  ) {
  1265.             
  1266.             if( cmdStatus == noErr ) {
  1267.             
  1268.                 if( gpFWSBP2DriverData->count > kMaxTransfer )
  1269.                     bufferLength = kMaxTransfer << 9;
  1270.                 else
  1271.                     bufferLength = gpFWSBP2DriverData->count << 9;
  1272.                     
  1273.                 if( !gpFWSBP2DriverData->isWrite && gpFWSBP2DriverData->doubleBuffer ) {
  1274.                     BlockMoveData( gpFWSBP2DriverData->dataBuffer, gpFWSBP2DriverData->buffer, bufferLength);
  1275.                 }
  1276.                 
  1277. #if VerifyWrites
  1278.                 if( gpFWSBP2DriverData->needsVerify && gpFWSBP2DriverData->command[0] == 0x2a) {
  1279.                 
  1280.                     // Read data for comparison
  1281.                     gpFWSBP2DriverData->whatWasWritten = (UInt8 *)gpFWSBP2DriverData->buffer;
  1282.                     SBP2DoReadWriteBlocks( false, gpFWSBP2DriverData->count, gpFWSBP2DriverData->sector, (char *)gpFWSBP2DriverData->verifyBuffer, false);                
  1283.                     break;
  1284.                 }
  1285.                 
  1286.                 if( gpFWSBP2DriverData->needsVerify && gpFWSBP2DriverData->command[0] != 0x2a ) {
  1287.  
  1288.                     // Do the comparison
  1289.                     for( x = 0; x < bufferLength; x++ ) { 
  1290.                     
  1291.                         if( gpFWSBP2DriverData->whatWasWritten[x] != gpFWSBP2DriverData->verifyBuffer[x] ) {
  1292.                             sprintf (debugStr, "pFWSBP2DiskDriver: Data mismatch! Written: %lx, Read: %lx, Offset %lx",
  1293.                                         (long) gpFWSBP2DriverData->whatWasWritten,
  1294.                                         (long) gpFWSBP2DriverData->verifyBuffer,
  1295.                                         (long) x);
  1296.                             DebugStr ((ConstStr255Param) c2pstr (debugStr));
  1297.                             break;
  1298.                         }
  1299.                     }
  1300.                     gpFWSBP2DriverData->needsVerify = false;
  1301.                 }
  1302. #endif
  1303.  
  1304.                 if( gpFWSBP2DriverData->xferLeft ) {
  1305.                     SBP2DoReadWriteBlocks( gpFWSBP2DriverData->isWrite, gpFWSBP2DriverData->xferLeft, gpFWSBP2DriverData->next_block, gpFWSBP2DriverData->next_buffer, false);
  1306.                     break;
  1307.                 }
  1308.                 
  1309.                 gpFWSBP2DriverData->dce->dCtlPosition += (gpFWSBP2DriverData->ioPB->ioActCount = gpFWSBP2DriverData->ioPB->ioReqCount);
  1310.                 gpFWSBP2DriverData->ioPending = false;
  1311.                 IOCommandIsComplete (gpFWSBP2DriverData->ioCommandID, noErr);
  1312.                 break;
  1313.             }
  1314.         }
  1315.         
  1316.         // If we got this far something bad happened so we should retry the current command
  1317.         if( gpFWSBP2DriverData->retriesLeft-- ) {
  1318.             SBP2DoReadWriteBlocks( gpFWSBP2DriverData->isWrite, gpFWSBP2DriverData->count, gpFWSBP2DriverData->sector, gpFWSBP2DriverData->buffer, false);
  1319.         }
  1320.         else {
  1321.             gpFWSBP2DriverData->ioPending = false;
  1322.             IOCommandIsComplete (gpFWSBP2DriverData->ioCommandID, ioErr);
  1323.         }
  1324.         break;
  1325.         
  1326.     case kSBP2NormalCommandReset:
  1327.         // Not much to do here. We'll retry when we get reconnectComplete notification.
  1328.         break;
  1329.  
  1330.     case kSBP2NormalCommandTimeout:
  1331.         // Fetch agent never sent us status. 
  1332.         
  1333. #if needLUNReset
  1334.         // Some SBP 2 devices have trouble recovering from error conditions. Preferably we would
  1335.         // reset the FA but some devices need to be kicked harder than others.
  1336.  
  1337.         FWSBP2Manage( gpFWSBP2DriverData->fwLUNReset_ID);
  1338.         return(noErr);
  1339. #else
  1340.         // Fetch agent never sent us status. Try resetting it. We'll retry from the completionProc
  1341.         status = FWSetAsynchCommandParams
  1342.             (gpFWSBP2DriverData->fwAGENT_RESET_ID,
  1343.              0,                                                    // generation - ignored
  1344.              gpFWSBP2DriverData->fetchAgent.addressHi,            // addr from login response
  1345.              gpFWSBP2DriverData->fetchAgent.addressLo + 4,        // + 4 to get AGENT_RESET
  1346.              (Ptr) gpFWSBP2DriverData,                            // any valid pointer will do
  1347.              4,                                                    // quadlet write
  1348.              0,                                                    // max payload - ignored
  1349.              8,                                                    // max retries
  1350.              0);                                                // no flags
  1351.         
  1352.         // Reset agent
  1353.         if (status == noErr)
  1354.         {
  1355.             FWWrite (gpFWSBP2DriverData->fwAGENT_RESET_ID);
  1356.             return(noErr);
  1357.         }
  1358. #endif
  1359.         break;
  1360.         
  1361.     case kSBP2UnsolicitedStatus:
  1362.     default:
  1363.         //DebugStr("\pUnsolicited status of some sort");
  1364.         break;
  1365.     }
  1366.  
  1367.     completedOrb = pFWClientSBP2NotifyParams->fwCommandObjectID;
  1368.  
  1369.     if( completedOrb == gpFWSBP2DriverData->orbID[kImmedORB] ) {
  1370.         gpFWSBP2DriverData->immedStatus = cmdStatus;
  1371.     }
  1372.  
  1373.     return( compStatus );
  1374.  
  1375. }
  1376.  
  1377.  
  1378. ////////////////////////////////////////////////////////////////////////////////
  1379. //
  1380. // SBPUnsolicitedStatusNotify
  1381. //
  1382. //   This routine is called when an unsolicited status is received.
  1383. //
  1384.  
  1385. static OSStatus SBPUnsolicitedStatusNotify(
  1386.     FWClientSBP2NotifyParamsPtr    pFWClientSBP2NotifyParams,
  1387.     UInt32                        *pCommandAcceptance)
  1388. {
  1389.     // Should now reset the Unsolocited Status Enabler - or else we'll never get any more.
  1390.     // This driver just receives one to prove that it can be done.
  1391.  
  1392.     *pCommandAcceptance = kFWClientCommandAcceptNoMore;
  1393.     return FWClientCommandIsComplete (pFWClientSBP2NotifyParams->fwClientInterfaceParams.fwClientCommandID, 0);
  1394. }
  1395.  
  1396.  
  1397. ////////////////////////////////////////////////////////////////////////////////
  1398. //
  1399. // SBP2Control
  1400. //
  1401. //   Mass storage control routine.
  1402. //
  1403.  
  1404. static OSStatus SBP2Control(
  1405.     AddressSpaceID                addressSpaceID,
  1406.     IOCommandID                    ioCommandID,
  1407.     IOCommandContents            ioCommandContents,
  1408.     IOCommandKind                ioCommandKind)
  1409. {
  1410.     OSStatus                    status = noErr;
  1411.  
  1412.     switch (((CntrlParam *) ioCommandContents.pb)->csCode)
  1413.     {
  1414.         case 5 :        // verifyTheDisc
  1415.             break;
  1416.  
  1417.         case 6 :        // formatTheDisc
  1418.             break;
  1419.  
  1420.         case 21 :        // getDriveIcon [HD]
  1421.         case 22 :        // getMediaIcon [HD]
  1422.             *((UInt32 *) &(((CntrlParam *) ioCommandContents.pb)->csParam[0])) =
  1423.                 (UInt32) (staticIconData);
  1424.             break;
  1425.  
  1426.         case 7 :        // ejectTheDisc
  1427.             status = noErr;
  1428.             gpFWSBP2DriverData->gotEject = true;
  1429.             // Spin down the drive...
  1430.             SBP2Logout();
  1431.             break;
  1432.         case 23 :        // driveInfo [HD]
  1433.         case 70 :        // setPowerMode [HD]
  1434.                         // Friendly drivers spin their disks down here.
  1435.         default :
  1436.             status = controlErr;
  1437.             break;
  1438.     }
  1439.  
  1440.     // We're complete.
  1441.     if (ioCommandKind == kImmediateIOCommandKind)
  1442.         return (status);
  1443.     else 
  1444.         return (IOCommandIsComplete (ioCommandID, status));
  1445. }
  1446.  
  1447.  
  1448. ////////////////////////////////////////////////////////////////////////////////
  1449. //
  1450. // SBP2Status
  1451. //
  1452. //   Mass storage status routine.
  1453. //
  1454.  
  1455. static OSStatus SBP2Status(
  1456.     AddressSpaceID                addressSpaceID,
  1457.     IOCommandID                    ioCommandID,
  1458.     IOCommandContents            ioCommandContents,
  1459.     IOCommandKind                ioCommandKind)
  1460. {
  1461.     OSStatus                    status = noErr;
  1462.     DriverGestaltParam            * gestaltPtr;
  1463.  
  1464.     switch (((CntrlParam *) ioCommandContents.pb)->csCode)
  1465.     {
  1466.         case kDriverGestaltCode:                    
  1467.             gestaltPtr = (DriverGestaltParam*)ioCommandContents.pb;
  1468.             switch(gestaltPtr->driverGestaltSelector) 
  1469.             {
  1470.                 case kdgSync:
  1471.                     GetDriverGestaltSyncResponse(gestaltPtr)->behavesSynchronously = false;
  1472.                     break;
  1473.                 
  1474.                 case kdgDeviceType:
  1475.                     GetDriverGestaltDevTResponse(gestaltPtr)->deviceType = kdgDiskType;    
  1476.                     break;
  1477.                 
  1478.                 case kdgInterface:
  1479.                     GetDriverGestaltIntfResponse(gestaltPtr)->interfaceType = kdgFireWireIntf;
  1480.                     break;
  1481.                 
  1482.                 case kdgVersion:
  1483.                     *GetDriverGestaltVersionResponse(gestaltPtr) = gFWDiskVersion;
  1484.                     break;
  1485.                 
  1486.                 case kdgBoot:
  1487.                     // Need to figure out what to do with this. !!! Vers 3.0
  1488.                     break;
  1489.                     
  1490.                 case kdgVMOptions:
  1491.                     // Don't let VM use this disk for a backing store.
  1492.                     GetDriverGestaltVMOptionsResponse(gestaltPtr)->vmOptions = kAllowVMNoneMask;
  1493.                     break;
  1494.                 
  1495.                 case kdgFlush:
  1496.                     // May be important if your device has a write cache!
  1497.                     GetDriverGestaltFlushResponse(gestaltPtr)->canFlush = false;
  1498.                     GetDriverGestaltFlushResponse(gestaltPtr)->needsFlush = false;
  1499.                     break;
  1500.  
  1501.                 default:
  1502.                     status = statusErr;
  1503.                     break;
  1504.             }
  1505.             break;
  1506.         case kDriveStatus:    // Do we care? Maybe for locked volumes
  1507.             BlockMove(&gpFWSBP2DriverData->driveStatus,&((CntrlParam *) ioCommandContents.pb)->csParam[0], sizeof(DrvSts));
  1508.             break;
  1509.         default :
  1510.             status = statusErr;
  1511.             break;
  1512.     }
  1513.  
  1514.     // We're complete.
  1515.     if (ioCommandKind == kImmediateIOCommandKind)
  1516.         return (status);
  1517.     else
  1518.         return (IOCommandIsComplete (ioCommandID, status));
  1519. }
  1520.  
  1521. ////////////////////////////////////////////////////////////////////////////////
  1522. //
  1523. // SBP2CalculateMediaSize
  1524. //
  1525. //   This routine performs a mode sense to calculate the media size
  1526. // This routine makes only synchronous calls, so it must be called only at task
  1527. // level.
  1528. //
  1529.  
  1530. static OSStatus SBP2CalculateMediaSize( void )
  1531. {
  1532.     FWCommandObjectID            orbID;
  1533.     FWAddress                    buffers[1];
  1534.     UInt32                        lengths[1];
  1535.     char                        buffer[256];
  1536. #define usesModeSense10 0
  1537. #if usesModeSense10
  1538.     UInt8                        command[12] = {0x5a, 0x08, 0x3e, 0, 0, 0, 0, 0, 0xff, 0, 0, 0};
  1539. #else
  1540.     UInt8                        command[12] = {0x25, 0, 0x00, 0, 0x00, 0, 0, 0, 0, 0, 0, 0};
  1541.     //UInt8                        command[12] = {0x1a, 0, 0x3e, 0, 0x7f, 0, 0, 0, 0, 0, 0, 0};
  1542. #endif
  1543.     OSStatus                    status;
  1544.  
  1545.     // !!! Comment this out if your drive supports Read Capacity    
  1546.     //gpFWSBP2DriverData->totalBlocks = 0x200000;
  1547.     //return noErr;
  1548.     
  1549.     orbID = gpFWSBP2DriverData->orbID[kImmedORB];    // Immediate ORB
  1550.     
  1551.     // Prepare the ORB.
  1552.     
  1553.     buffers[0].addressHi = 0;
  1554.     buffers[0].addressLo = (UInt32) buffer;
  1555.     lengths[0] = 0x08;
  1556.     status = FWSetSBP2NormalCommandBuffers (orbID, 1, buffers, lengths);
  1557.  
  1558.     if (status == noErr)
  1559.         status = FWSetSBP2NormalCommandCommand (orbID, (Ptr) command, 12);
  1560.     
  1561.     if (status == noErr)
  1562.         status = FWSetSBP2NormalCommandTimeout (orbID, durationMillisecond * 1000);
  1563.     
  1564.     if (status == noErr)
  1565.         status = FWSetSBP2NormalCommandFlags (orbID,
  1566.                                               kSBP2CommandTransferDataFromTarget |
  1567.                                               kSBP2CommandCompleteNotify |
  1568.                                               kSBP2CommandImmediate |
  1569.                                               kSBP2CommandNormalORB);
  1570.     
  1571.     if (status == noErr)
  1572.         status = FWSetFWCommandFlags (orbID, kFWCommandSyncFlag);
  1573.         
  1574.      *(long*)&buffer[0] = 0;
  1575.     
  1576.     gpFWSBP2DriverData->immedStatus = ioInProgress; // Remember we're busy with this guy
  1577.     
  1578.     if (status == noErr)
  1579.         status = FWAppendSBP2Command (orbID);
  1580.     
  1581.     // The Append command was synchronous.  When it returns, the command has been
  1582.     // appended to the target.  But the target probably has not executed the command yet.
  1583.     
  1584.     if (status == noErr)
  1585.     {
  1586.         // Remember kiddies - don't do this at interrupt time!
  1587.         while( gpFWSBP2DriverData->immedStatus == ioInProgress )
  1588.             ;
  1589.         
  1590.         // Really need to try and reset the drive here but I'm not feeling up to it at the moment.
  1591.         // Perhaps a LogicalUnitReset might be in order...
  1592.         
  1593.         if( *(long*)&buffer[0] == 0 )
  1594.             return( ioErr );
  1595.             
  1596.         gpFWSBP2DriverData->totalBlocks = *(long*)&buffer[0] - 1;
  1597.     }
  1598.     else 
  1599.         return( ioErr );
  1600.     
  1601.     return noErr;
  1602. }
  1603.  
  1604.  
  1605. ////////////////////////////////////////////////////////////////////////////////
  1606. //
  1607. // SBP2TUR
  1608. //
  1609. //   Some drives need this 
  1610. //
  1611.  
  1612. static OSStatus SBP2TUR( Boolean sync )
  1613. {
  1614.     FWCommandObjectID            orbID;
  1615.     UInt8                        * command;
  1616.     OSStatus                    status;
  1617.  
  1618.         
  1619.     if( sync )
  1620.         orbID = orbID = gpFWSBP2DriverData->orbID[kImmedORB];
  1621.     else {
  1622.         orbID = gpFWSBP2DriverData->orbID[gpFWSBP2DriverData->currentORB];
  1623.         
  1624.         // Switch to the other ORB for next transaction
  1625.         gpFWSBP2DriverData->currentORB = ( gpFWSBP2DriverData->currentORB ? 0 : 1);
  1626.     }
  1627.     
  1628.     command = &gpFWSBP2DriverData->command[0];
  1629.     
  1630.     command[0] = 0x00;                                // TUR
  1631.     command[1] = 0;    
  1632.     command[2] = 0;    
  1633.     command[3] = 0;
  1634.     command[4] = 0;
  1635.     command[5] = 0;
  1636.     command[6] = 0;
  1637.     command[7] = 0;
  1638.     command[8] = 0;
  1639.     command[9] = 0;
  1640.     command[10] = 0;
  1641.     command[11] = 0;
  1642.  
  1643.     // Prepare the ORB.
  1644.     
  1645.     gpFWSBP2DriverData->buffers[0].addressHi = 0;
  1646.     gpFWSBP2DriverData->buffers[0].addressLo = (UInt32) gpFWSBP2DriverData->aBuffer;
  1647.     gpFWSBP2DriverData->lengths[0] = 0;
  1648.     FWSetSBP2NormalCommandBuffers (orbID, 0, gpFWSBP2DriverData->buffers, gpFWSBP2DriverData->lengths);
  1649.     
  1650.     status = FWSetSBP2NormalCommandCommand (orbID, (Ptr) command, 12);
  1651.     
  1652.     if (status == noErr)
  1653.         status = FWSetSBP2NormalCommandTimeout (orbID, durationMillisecond * 5000);
  1654.     
  1655.     if (status == noErr)
  1656.         status = FWSetSBP2NormalCommandFlags (orbID,
  1657.                                               kSBP2CommandCompleteNotify |
  1658.                                               kSBP2CommandImmediate |
  1659.                                               kSBP2CommandNormalORB);
  1660.             
  1661.     if( sync ) {
  1662.         if (status == noErr)
  1663.             status = FWSetFWCommandFlags (orbID, kFWCommandSyncFlag);
  1664.     }
  1665.     else {
  1666.         if (status == noErr)
  1667.             status = FWSetFWCommandFlags (orbID, 0);
  1668.     }
  1669.     
  1670.     gpFWSBP2DriverData->immedStatus = ioInProgress; // Remember we're busy with this guy
  1671.  
  1672.     if (status == noErr) {
  1673.         status = FWAppendSBP2Command (orbID);
  1674.         //if( status )
  1675.         //    DebugStr("\pFailed Append");
  1676.     }
  1677.     
  1678.     // The Append command was synchronous.  When it returns, the command has been
  1679.     // appended to the target.  But the target probably has not executed the command yet.
  1680.     
  1681.     if( (status == noErr) && sync )
  1682.     {
  1683.         // Wait for completion
  1684.         // Remember kiddies - don't do this at interrupt time!
  1685.         while( gpFWSBP2DriverData->immedStatus == ioInProgress )
  1686.             ;
  1687.         status = gpFWSBP2DriverData->immedStatus;
  1688.     }
  1689.     
  1690.     if( (status == noErr) && !sync ) {
  1691.         return( ioInProgress );
  1692.     }
  1693.         
  1694.     return status;
  1695. }
  1696.  
  1697.  
  1698. ////////////////////////////////////////////////////////////////////////////////
  1699. //
  1700. // ResetFACompletionProc
  1701. //
  1702. void
  1703. ResetFACompletionProc(
  1704.     FWCommandObjectID            fwCommandObjectID,
  1705.     OSStatus                    commandStatus,
  1706.     UInt32                        completionProcData)
  1707. {
  1708.     // Had to reset the fetch agent. If doing an IO the restart it. Otherwise report
  1709.     // and error (was an immediate or utility command).
  1710.     if( gpFWSBP2DriverData->ioPending ) {
  1711.         if( gpFWSBP2DriverData->retriesLeft-- ) {
  1712.             SBP2DoReadWriteBlocks( gpFWSBP2DriverData->isWrite, gpFWSBP2DriverData->count, gpFWSBP2DriverData->sector, gpFWSBP2DriverData->buffer, false);
  1713.         }
  1714.         else {
  1715.             gpFWSBP2DriverData->ioPending = false;
  1716.             IOCommandIsComplete (gpFWSBP2DriverData->ioCommandID, ioErr);
  1717.         }
  1718.     }
  1719.     else {
  1720.         gpFWSBP2DriverData->immedStatus = -1;    // If we had to reset the fetch agent we got an error...
  1721.     }
  1722. }
  1723.  
  1724. ////////////////////////////////////////////////////////////////////////////////
  1725. //
  1726. // LoginCompletionProc
  1727. //
  1728. void
  1729. LoginCompletionProc(
  1730.     FWCommandObjectID            fwCommandObjectID,
  1731.     OSStatus                    commandStatus,
  1732.     UInt32                        completionProcData)
  1733. {
  1734.     gpFWSBP2DriverData->loginObjBusy = false;
  1735.     
  1736.     // If this is an attempt to clear an error condition - try logging in again
  1737.     if( gpFWSBP2DriverData->reLogin ) {
  1738.         gpFWSBP2DriverData->reLogin = false;
  1739.         FWSBP2Login (gpFWSBP2DriverData->loginCommandID);
  1740.     }
  1741. }
  1742.  
  1743. ////////////////////////////////////////////////////////////////////////////////
  1744. //
  1745. // ManageCompletionProc
  1746. //
  1747. void
  1748. ManageCompletionProc(
  1749.     FWCommandObjectID            fwCommandObjectID,
  1750.     OSStatus                    commandStatus,
  1751.     UInt32                        completionProcData)
  1752. {
  1753.     OSStatus                    status;
  1754.  
  1755.     status = FWSetAsynchCommandParams
  1756.         (gpFWSBP2DriverData->fwAGENT_RESET_ID,
  1757.          0,                                                    // generation - ignored
  1758.          gpFWSBP2DriverData->fetchAgent.addressHi,            // addr from login response
  1759.          gpFWSBP2DriverData->fetchAgent.addressLo + 4,        // + 4 to get AGENT_RESET
  1760.          (Ptr) gpFWSBP2DriverData,                            // any valid pointer will do
  1761.          4,                                                    // quadlet write
  1762.          0,                                                    // max payload - ignored
  1763.          8,                                                    // max retries
  1764.          0);                                                // no flags
  1765.     
  1766.     // Reset agent
  1767.     if (status == noErr)
  1768.     {
  1769.         FWWrite (gpFWSBP2DriverData->fwAGENT_RESET_ID);
  1770.     }
  1771. }
  1772.  
  1773.  
  1774. ////////////////////////////////////////////////////////////////////////////////
  1775. //
  1776. // ReconnectReadCompletionProc
  1777. //
  1778. void
  1779. ReconnectReadCompletionProc(
  1780.     FWCommandObjectID            fwCommandObjectID,
  1781.     OSStatus                    commandStatus,
  1782.     UInt32                        completionProcData)
  1783. {
  1784.     OSStatus                     status;
  1785.  
  1786.     if( !commandStatus ) {
  1787.         // Login again
  1788.         status = FWSBP2Login (gpFWSBP2DriverData->loginCommandID);
  1789.     }
  1790.     if( status || commandStatus ) {
  1791.         gpFWSBP2DriverData->lookForDriveReqs = 0;
  1792.     }
  1793. }
  1794.  
  1795. ////////////////////////////////////////////////////////////////////////////////
  1796. //
  1797. // ReplugCompletionProc
  1798. //
  1799. void
  1800. ReplugCompletionProc(
  1801.     FWCommandObjectID            fwCommandObjectID,
  1802.     OSStatus                    commandStatus,
  1803.     UInt32                        completionProcData)
  1804. {
  1805.     gpFWSBP2DriverData->wait4Replug = false;
  1806.     if( !commandStatus ) {
  1807.         // We could just log back into the drive again here but I've found its better to rely
  1808.         // on the look for the device after reset notification which will keep functioning even
  1809.         // after the user does a Command-. This way if the user realizes they made a mistake and
  1810.         // plug the drive back in we'll see it and login correctly.
  1811.         gpFWSBP2DriverData->returnDiskErr = false;
  1812.         
  1813.         // Go look for the drive and login if necessary.
  1814.         // Note that this guy is protected by a semaphore so that we won't try to use
  1815.         // either fwReplugID or loginCommandID more than once.
  1816.         FWSBPLookForDrive();
  1817.     }
  1818.     else {
  1819.         // return ioErr for our pending command and all subsequent commands
  1820.         if( gpFWSBP2DriverData->ioPending ) 
  1821.             IOCommandIsComplete (gpFWSBP2DriverData->ioCommandID, ioErr);
  1822.         gpFWSBP2DriverData->returnDiskErr = true;
  1823.         
  1824.     }
  1825.  
  1826. }
  1827.  
  1828.  
  1829. ////////////////////////////////////////////////////////////////////////////////
  1830. //
  1831. // FWSBPLookForDrive
  1832. //
  1833. // Starts a Read, Login, Retry thread for our drive. Used after a reset or if
  1834. // we somehow got ORB status while not logged in.
  1835. //
  1836. static void FWSBPLookForDrive( void )
  1837. {
  1838.     OSStatus                    status = noErr;
  1839.  
  1840.     if( gpFWSBP2DriverData->wait4Replug )    
  1841.         return;    // Waiting for FSL to tell us what to do
  1842.  
  1843.     if( !gpFWSBP2DriverData->loggedIn ) {
  1844.         
  1845.         if( !IncrementAtomic( &gpFWSBP2DriverData->lookForDriveReqs ) ) {
  1846.     
  1847.             // We've been disconnected from our device and we need to know
  1848.             // whether it came back (as a result of this reset or re-plug notification.
  1849.             // Seems like the easiest way is to try a read from the device's CSR ROM.
  1850.             // If it works we can try to login and resume any command we had pending.
  1851.         
  1852.             status = FWSetAsynchCommandParams
  1853.                         (gpFWSBP2DriverData->fwReconnectID,
  1854.                          0,
  1855.                          0xffff,
  1856.                          0xf0000400,    
  1857.                          (Ptr) &gpFWSBP2DriverData->bitBucket,                        // Actual data doesn't matter
  1858.                          4,                                                            // length of params
  1859.                          4,                                                            // max payload
  1860.                          4,                                                            // max retries
  1861.                          0);                                                        // 
  1862.                          
  1863.             if (status == noErr)
  1864.             {
  1865.                 status = FWRead (gpFWSBP2DriverData->fwReconnectID);
  1866.                 
  1867.             }
  1868.             
  1869.             if( status ) {
  1870.                 gpFWSBP2DriverData->lookForDriveReqs = 0;
  1871.             }
  1872.  
  1873.         }
  1874.     }
  1875. }
  1876.  
  1877. ////////////////////////////////////////////////////////////////////////////////
  1878. //
  1879. // FWSBPResetNotify
  1880. //
  1881.  
  1882. static OSStatus    FWSBPResetNotify(
  1883.     FWClientInterfaceParamsPtr    pFWClientInterfaceParams,
  1884.     UInt32                        *pCommandAcceptance)
  1885. {
  1886.  
  1887.     FWSBPLookForDrive();
  1888.  
  1889.     // Complete FireWire client command.
  1890.     FWClientCommandIsComplete (pFWClientInterfaceParams->fwClientCommandID, noErr);
  1891.  
  1892.     // Return command acceptance.
  1893.     //zzz is this the right way?  If we've completed the command, we can accept more.
  1894.     *pCommandAcceptance = kFWClientCommandAcceptNoMore;
  1895.  
  1896.     return noErr;
  1897. }
  1898.  
  1899. // Place this code somewhere if you want to try and re-program your CSR ROM on a Symbios
  1900. // native bridge. Be real, real careful though as if you get it wrong you can't do it again
  1901. // if you flash something that doesn't work. Since that's what happened to me I won't 
  1902. // guarantee that this ROM will work. Your mileage may vary
  1903. //
  1904. static OSStatus FlashSymbiosROM( void )
  1905. {
  1906.     UInt32                        x;
  1907.     FWCommandObjectID            commandID;
  1908.     OSStatus                    allocStatus;
  1909.     UInt32                        ROMData[]      = {  /*0xFB000000,*/ 0x31333934, 0x00ff5000, 0x00a0b800,
  1910.                                                    0x00005000, 0x00067A52, 0x0C0083C0, 0x0300A0B8,
  1911.                                                    
  1912.                                                    0x8100000F, 0x0400500A, 0x81000015, 0xD1000001,
  1913.                                                    0x00067752, 0x1200609E, 0x13010483, 0x5400C000,
  1914.                                                    
  1915.                                                    0x3A401E08, 0x14000000, 0xD4000001, 0x000329A2,
  1916.                                                    0x0400500A, 0x8100000A, 0x8200000E, 0x0007BD5D,
  1917.                                                    
  1918.                                                    0x00000000, 0x00000000, 0x53594D42, 0x494F5320,
  1919.                                                    0x4C4F4749, 0x432C2049, 0x4E432E00, 0x00044469,
  1920.                                                     
  1921.                                                    0x00000000, 0x00000000, 0x53594D42, 0x494F5300,
  1922.                                                    0x000AE09E, 0x00000000, 0x00000000, 0x53594D31,
  1923.                                                    
  1924.                                                    0x33465735, 0x30302D44, 0x49534B20, 0x44524956,
  1925.                                                    0x45000000, 0x00000000, 0x00000000,
  1926.                                                    
  1927.                                                    0x8A000000, 0x00000000, 0x00000000, 0x00000000,
  1928.                                                    0x00000000, 0x00000000, 0x00000000, 0x00000000,
  1929.                                                   
  1930.                                                    0xFEEDFACE, 0xDEADBEEF, 0x00000000, 0x00000000,
  1931.                                                    0x00000000, 0x00000000, 0x00000000,
  1932.                                                    
  1933.                                                    0x0F000000, 0x00000000, 0x00000000, 0x00000000,
  1934.                                                    0x00000000, 0x00000000, 0x00000000, 0x00000000,
  1935.                                                   
  1936.                                                    0xFEEDFACE, 0xDEADBEEF, 0x00000000, 0x00000000,
  1937.                                                    0x00000000, 0x00000000, 0x00000000 };
  1938.  
  1939.  
  1940.     UInt32                        params;
  1941.     UInt32                        targetNodeID, generationNumber;
  1942.     OSStatus                    status;
  1943.     params = 0x042E19A8;
  1944.  
  1945.  
  1946.     DebugStr("\pAbout to flash ROM");
  1947.  
  1948.     allocStatus = status = FWAllocateAsynchCommandObject (&commandID);
  1949.     
  1950.     if (status == noErr)
  1951.         status = FWSetFWCommandParams (commandID,
  1952.                                        gpFWSBP2DriverData->fwDriverID,
  1953.                                        kFWCommandSyncFlag, 0, 0);
  1954.  
  1955.     if (status == noErr)
  1956.         status = FWGetNodeID (gpFWSBP2DriverData->fwDriverID,
  1957.                               &targetNodeID,
  1958.                               &generationNumber);
  1959.  
  1960.     if (status == noErr) for( x = 0; x < 77 ; x++ ) {
  1961.         status = FWSetAsynchCommandParams
  1962.                     (commandID,
  1963.                      generationNumber,
  1964.                      0xffff,
  1965.                      0xf0000400 + (x<<2),    
  1966.                      (Ptr) &ROMData[x],
  1967.                      4,                                                            // length of params
  1968.                      4,                                                            // max payload - ignored
  1969.                      8,                                                            // max retries
  1970.                      kFWAsynchFailOnBusReset);                                    // give up if bus reset
  1971.                      
  1972.         // Store new settings
  1973.         if (status == noErr)
  1974.         {
  1975.             // Note, previously made this a synchronous command object
  1976.             //DebugStr("\pWrite out ROM values");
  1977.             status = FWWrite (commandID);
  1978.             
  1979.         }
  1980.         DelayForHardware(DurationToAbsolute(durationMillisecond * 10));
  1981.         
  1982.     }
  1983.     
  1984.     status = FWSetAsynchCommandParams
  1985.                 (commandID,
  1986.                  generationNumber,
  1987.                  0xffff,
  1988.                  0xf0000400,    
  1989.                  (Ptr) ¶ms,
  1990.                  4,                                                            // length of params
  1991.                  4,                                                            // max payload - ignored
  1992.                  8,                                                            // max retries
  1993.                  kFWAsynchFailOnBusReset);                                    // give up if bus reset
  1994.  
  1995.     // Store new settings
  1996.     if (status == noErr)
  1997.     {
  1998.         // Note, previously made this a synchronous command object
  1999.         //DebugStr("\pWrite 400");
  2000.         status = FWWrite (commandID);
  2001.         
  2002.     }
  2003.     DelayForHardware(DurationToAbsolute(durationMillisecond * 10));
  2004.         
  2005.     
  2006.     status = FWSetAsynchCommandParams
  2007.                 (commandID,
  2008.                  generationNumber,
  2009.                  0xffff,
  2010.                  0xf000000c,    
  2011.                  (Ptr) ¶ms,
  2012.                  4,                                                            // length of params
  2013.                  4,                                                            // max payload - ignored
  2014.                  8,                                                            // max retries
  2015.                  kFWAsynchFailOnBusReset);                                    // give up if bus reset
  2016.  
  2017.     // Store new settings
  2018.     if (status == noErr)
  2019.     {
  2020.         // Note, previously made this a synchronous command object
  2021.         //DebugStr("\pWrite Reset");
  2022.         status = FWWrite (commandID);
  2023.         
  2024.     }
  2025.     DelayForHardware(DurationToAbsolute(durationMillisecond * 10));
  2026.         
  2027.     if (allocStatus == noErr)
  2028.         FWDeallocateFWCommandObject (commandID);
  2029.     
  2030.     DebugStr("\pDone - reset the bus and the Mac (also probably replace this driver to NOT flash ROM again)");
  2031.     return(noErr);
  2032. }
  2033.  
  2034.  
  2035. ///////////////////////////////////////////////
  2036. //
  2037. // Set the BUSY_TIMEOUT register in the drive.
  2038. // This all runs at task level during the install.
  2039. //
  2040.  
  2041. static OSStatus SetBUSY_TIMEOUT (void)
  2042. {
  2043.     FWCommandObjectID            commandID;
  2044.     UInt32                        busyTimeout;
  2045.     OSStatus                    allocStatus;
  2046.     OSStatus                    status = noErr;
  2047.     
  2048.     // Prepare a command object to quadlet read/write the BUSY_TIMEOUT register at 0x210.
  2049.     
  2050.     allocStatus = status = FWAllocateAsynchCommandObject (&commandID);
  2051.     
  2052.     if (status == noErr)
  2053.         status = FWSetFWCommandParams (commandID,
  2054.                                        gpFWSBP2DriverData->fwDriverID,
  2055.                                        kFWCommandSyncFlag, 0, 0);
  2056.  
  2057.     if (status == noErr)
  2058.         status = FWSetAsynchCommandParams
  2059.                     (commandID, 0, 0xffff, 0xf0000210, (Ptr) &busyTimeout, 4, 4, 8, 0);
  2060.     
  2061.     // Read old value, set our desired retry count, and write it back.
  2062.     
  2063.     if (status == noErr)
  2064.         status = FWRead (commandID);
  2065.  
  2066.     if (status == noErr)
  2067.     {
  2068.         busyTimeout &= 0xfffffff0;        // Preserve other bits
  2069.         busyTimeout |= 0x0000000f;        // Set retry count to 15
  2070.         
  2071.         status = FWWrite (commandID);
  2072.     }
  2073.     
  2074.     if (allocStatus == noErr)
  2075.         FWDeallocateFWCommandObject (commandID);
  2076.         
  2077.     return status;
  2078. }
  2079.  
  2080.  
  2081.  
  2082.